# -*- coding: utf-8 -*-
# File : file_distribute.py
# Author: taoyahui
# Date : 2021/8/8
import sys

sys.path.append('..')

from os import path
from utils import mysql_util
from results import *
import json
from tasks import patch_deploy
import requests
from utils.mongo_util import *
import time
from tasks import windows_ansible, linux_ansible
from application_factory.models import InventoryCls
from fabric import Connection
from utils.log_util import logger

file_path = '/usr/local/patch-data/file'


def send_file_lib(strategy):
    group_id_list = patch_deploy.find_relate_inventory_group(strategy.inventory_group_id)
    group_id_list = [str(x) for x in group_id_list]
    inventory_group_id_list_str = ",".join(group_id_list)
    # 找到资产组所有的资产
    find_inventory_sql = f"select * from inventory " \
                         f"where group_id in ({inventory_group_id_list_str}) and username is not null and os is not null"
    inventory_res_list = mysql_util.exec_sql_new(find_inventory_sql)
    inventory_list = [InventoryCls(inventory_res) for inventory_res in inventory_res_list]

    # 将资产组中的hosts文件分类成linux系统和windows系统，然后再做文件分发
    win_hosts = []
    linux_hosts = []
    for inventory in inventory_list:
        if 'windows' in inventory.os.lower():
            win_hosts.append(inventory.ip)
        else:
            linux_hosts.append(inventory.ip)

    if len(win_hosts) > 0:
        logger.info(
            f"send_file_lib -> Start distribute ****windows**** hosts file, Strategy name is {strategy.strategy_name}")
        file_transfer_core(strategy, win_hosts, 'windows')

    if len(linux_hosts) > 0:
        logger.info(
            f"send_file_lib -> Start distribute ****linux**** hosts file, Strategy name is {strategy.strategy_name}")
        file_transfer_core(strategy, linux_hosts, 'linux')
    return success_result


def file_transfer_core(strategy, hosts, os):
    file_libs = json.loads(strategy.file_library_ids)
    distribute_results = []
    for file in file_libs:
        id = file['id']
        find_file_sql = f"Select source_file_name from file_library where id = {id}"
        res_list = mysql_util.exec_sql_new(find_file_sql)

        if res_list is not None and len(res_list) > 0:
            res = res_list[0]
            file_name = res[0]
            if strategy.save_path is None:
                strategy.save_path = ''
            save_path = path.join(strategy.strategy_name, strategy.save_path)

            result = requests.post("http://localhost:5002/distribute_file", json={"hosts": hosts,
                                                                                  "file_name": file_name,
                                                                                  "file_dir": save_path,
                                                                                  'os': os})
            distribute_results.append(result.json())

    print(f"***** file distribute results is {distribute_results}")
    file_distribute_log(strategy_id=strategy.strategy_id, strategy_name=strategy.strategy_name,
                        timestamp=int(time.time()), results=distribute_results)


def get_inventory_list(ips):
    inventory_list = []
    for ip in ips:
        find_inventory_sql = f"Select * from inventory where ip = '{ip}' limit 1"
        res = mysql_util.exec_sql_new(find_inventory_sql)
        if res is not None and len(res) > 0:
            inventory_res = res[0]
            inventory = InventoryCls(inventory_res)
            inventory_list.append(inventory)

    return inventory_list


def win_copy_remote_source(file_name, save_dir, ips):
    """
    windows 主机传输文件
    :param file_name:
    :param save_dir:
    :param ips:
    :return:
    """
    inventory_list = get_inventory_list(ips)
    return copy_source(file_name, save_dir, inventory_list)


def linux_copy_source(file_name, save_dir, ips):
    """
    linux 远程复制文件
    :param file_name:
    :param save_dir:
    :param inventory_list:
    :return:
    """
    # inventory_list = get_inventory_list(ips)
    # src = path.join(file_path, file_name)
    # dist = path.join('/root', save_dir, file_name)
    # for inventory in inventory_list:
    #     try:
    #         c = Connection(f"{inventory.username}@{inventory.ip}", port=inventory.port, connect_kwargs={'password': inventory.password})
    #         c.put(src, dist)
    #     except Exception as e:
    #         logger.info(f"linux_copy_source -> Error When Transport file-> {file_name} to IP -> {inventory.ip}. "
    #                     f"Reason is {e}")
    #         return 1
    #     finally:
    #         c.close()
    # return 0
    inventory_list = get_inventory_list(ips)
    dest_path = '/root'
    remote_ips = [str(inventory.ip) for inventory in inventory_list]
    if save_dir is not None:
        dest_path = path.join('/root', save_dir)
    play_source = dict(
        name="Ansible Play",
        hosts=remote_ips,
        gather_facts='no',
        tasks=[
            dict(action=dict(module='copy', args=f"src={path.join(file_path, file_name)} dest={dest_path}")),
        ]
    )
    return linux_ansible.dynamic_exec(play_source, inventory_list)


def copy_source(file_name, save_dir, inventory_list):
    """
    (ansible 项目使用) 复制文件给远端IP
    :param inventory_list:
    :param file_name:
    :param save_dir:
    :param remote_ip:
    :return:
    """
    dest_path = 'C:/'
    remote_ips = [str(inventory.ip) for inventory in inventory_list]
    if save_dir is not None:
        dest_path = path.join('C:/', save_dir)
    play_source = dict(
        name="Ansible Play",
        hosts=remote_ips,
        gather_facts='no',
        tasks=[
            dict(action=dict(module='win_copy', args=dict(src=path.join(file_path, file_name), dest=dest_path))),
        ]
    )
    return windows_ansible.dynamic_exec(play_source, inventory_list)

    # if int(result) == 0:


# def main(play_source):
#
#     loader = DataLoader()
#     inventory = InventoryManager(loader=loader, sources=(path.join(get_root_dir(), 'playbook', 'hosts')))
#     variable_manager = VariableManager(loader=loader, inventory=inventory)
#     play = Play().load(play_source, variable_manager=variable_manager, loader=loader)
#
#     passwords = {} #dict(vault_pass='123456')
#     tqm = TaskQueueManager(
#         inventory=inventory,
#         variable_manager=variable_manager,
#         loader=loader,
#         passwords=passwords,
#         #stdout_callback=results_callback,  # Use our custom callback instead of the ``default`` callback plugin, which prints to stdout
#     )
#     try:
#         result = tqm.run(play)  # most interesting data for a play is actually sent to the callback's methods
#     finally:
#         # we always need to cleanup child procs and the structures we use to communicate with them
#         tqm.cleanup()
#         if loader:
#             loader.cleanup_all_tmp_files()
#     return result


def save_result(result, hosts, file_name):
    host_len = len(hosts)
    fail_msg = {}
    fail_msg['counts_success'] = 0
    fail_msg['counts_fail'] = 0
    fail_msg['counts_unreachable'] = 0
    fail_msg['failed'] = {}
    fail_msg['unreachable'] = {}
    if int(result) == 0:
        fail_msg['counts_success'] += host_len
    else:
        host_str = "_".join(hosts)
        host_str_new = host_str.replace(".", "_")
        fail_msg['counts_unreachable'] = host_len
        fail_msg['unreachable'][host_str_new] = "*" * 5 + f" Send File Contains Problem in {host_str}" + "*" * 5
    save_result = {'name': file_name, 'result': fail_msg}
    return save_result


# 使用mongodb 记录文件分发的日志
def file_distribute_log(strategy_id, strategy_name, timestamp, results):
    res = {
        'strategy_id': strategy_id,
        'strategy_name': strategy_name,
        'timestamp': timestamp,
        'result': results
    }
    return insert_one_document('patch_distribute', 'strategy_log', res)


if __name__ == "__main__":
    send_file_lib('', '', 34)
